/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frame.c                                            */
/*  NOTE      = 整体入口                                           */
/*  DATE      = 2014/10/08 by yaohl                                */
/*******************************************************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <getopt.h>

#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/thread.h>

#include <nids.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frhash2.h"
#include "frstr.h"
#include "frtimer.h"
#include "conntrack.h"
#include "frame_params.h"
#include "frame.h"
#include "frct_mng.h"
#include "frct_hash.h"
#include "frct_expect.h"
#include "frtask_mng.h"
#include "frmodule_mng.h"
#include "frproto_mng.h"
#include "frproto_l7default.h"
#include "frtask_do.h"
#include "frfilter.h"
#include "frcmd_server.h"
#include "frreport_mng.h"
#include "frstat_module.h"
#include "frstat_system.h"
#include "frstat_thread.h"
#include "frstat_server.h"

typedef struct __apm_packets {
    struct timeval st_start_sec;

    unsigned long ul_rx;    //RX packets

    unsigned long ul_syn;   //syn packets
    unsigned long ul_fin;   //fin/reset packets
}Frapm_packets;

/* 调试用 1;否则 0 */
#define APM_DEBUG_UDP       0

/* 程序运行标识 */
int g_i_flag_run =1;
int g_i_task_chk_timer=FR_NO; /* 用于判断 g_thread_id_do_timer 线程是否在运行*/

/* event_base */
struct event_base *g_p_st_ebase = NULL;
FR_STATIC pthread_t g_thread_id_cmd_line=0;
FR_STATIC pthread_t g_thread_id_do_timer=0;

/* 任务处理线程个数  */
FR_STATIC int g_i_do_task_cnt=1;
FR_STATIC pthread_t *g_p_thread_id_do_task=NULL;

/* 统计线程个数  */
#define APM_STAT_CNT    5
FR_STATIC pthread_t g_thread_id_stat[APM_STAT_CNT];


FR_STATIC unsigned int g_ui_threads=1;  //总线程个数(包括主线程)
FR_STATIC int g_i_after_nids_sec=2;     //默认nids退出后等待10sec

#define APM_STAT_ERVER_CHECK_TIME       600
#define APM_STAT_RELATED_CHECK_TIME     600

/* 数据包统计信息 */
FR_STATIC Frapm_packets g_st_apm_packets;

unsigned int frame_threads_cnt(void)
{
    return g_ui_threads;
}

/*******************************************************************************
*  FUNC     :  数据包统计信息出力
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_stat_packet_report(struct timeval *p_st_tv_now)
{
#ifdef FRDBG_PACKET_STAT
    unsigned long ul_run_time=0L;

    ul_run_time = (p_st_tv_now->tv_sec - g_st_apm_packets.st_start_sec.tv_sec) * 1000000
                + (p_st_tv_now->tv_usec - g_st_apm_packets.st_start_sec.tv_usec);
    //出力统计信息
    printf("%lu.%06lusec\trx=%lu\tsyn=%lu\tfin=%lu\n"
            , (unsigned long)(ul_run_time / 1000000)
            , ul_run_time % 1000000
            , g_st_apm_packets.ul_rx
            , g_st_apm_packets.ul_syn
            , g_st_apm_packets.ul_fin);
#endif
    return;
}

/*******************************************************************************
*  FUNC     :  统计模块初始化
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_stat_init(void)
{
    frstat_module_init(1);
    frstat_system_init(1);
    frstat_thread_init(1);
    frstat_server_init(1);
    return;
}

/*******************************************************************************
*  FUNC     :  统计模块释放
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_stat_destory(void)
{
    frstat_server_destory();
    frstat_thread_destory();
    frstat_system_destroy();
    frstat_module_destory();

    return;
}

/*******************************************************************************
*  FUNC     :  模块信息统计
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_module(void *arg)
{
    struct timeval st_time_start,st_time_end, st_delay;
    long l_time_diff=0;

    do
    {
        gettimeofday(&st_time_start, NULL);

        frstat_module_bps();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 0)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  系统信息统计
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_system(void *arg)
{
    struct timeval st_time_start,st_time_end, st_delay;
    long l_time_diff=0;

    do
    {
        gettimeofday(&st_time_start, NULL);

        frstat_system_count();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 0)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  数据处理线程的相关信息统计
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_thread(void *arg)
{
    struct timeval st_time_start,st_time_end , st_delay;
    long l_time_diff=0;

    do
    {
        gettimeofday(&st_time_start, NULL);

        frstat_thread_count();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 0)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  数据处理线程的相关信息统计
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_server(void *arg)
{
    struct timeval st_time_start,st_time_end , st_delay;
    long l_time_diff=0, l_count=0;

    do
    {
        gettimeofday(&st_time_start, NULL);

        frstat_server_count();

        if(l_count++ % 60 == 0)
        {
            l_count = 0;
            frstat_server_check_timeouts(APM_STAT_ERVER_CHECK_TIME);
            frstat_related_check_timeouts(APM_STAT_RELATED_CHECK_TIME);
        }

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 0)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  框架数据包信息统计
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_packet(void *arg)
{
    struct timeval st_time_start,st_time_end, st_delay;
    long l_time_diff=0;

    do
    {
        gettimeofday(&st_time_start, NULL);

        __frame_stat_packet_report(&st_time_start);

        memset(&g_st_apm_packets, 0x00, sizeof(Frapm_packets));
        g_st_apm_packets.st_start_sec = st_time_start;

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 20)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  数据包信息按每秒统计并出力
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_packet_stata_add(int i_data_type)
{
#ifdef FRDBG_PACKET_STAT
    //数据包累计
    g_st_apm_packets.ul_rx++;

    switch(i_data_type)
    {
        case APM_CONNECT_SYN_SENT:
            g_st_apm_packets.ul_syn++;
            break;
        case APM_CONNECT_CLOSED:
            g_st_apm_packets.ul_fin++;
            break;
        default:
            break;
    }
#endif
    return;
}

/*******************************************************************************
*  FUNC     :  更改nids解析时，是否检查checksum
*  ARGS     :  i_flag_enable      (FR_YES:设定checksum有效; FR_NO:设定checksum无效)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_chg_chksum(int i_flag_enable)
{
    FR_STATIC struct nids_chksum_ctl ctl;

    ctl.netaddr = 0;
    ctl.mask = 0;

    //check sum 有效
    if(i_flag_enable == FR_YES)
    {
        ctl.action = NIDS_DO_CHKSUM;
        nids_register_chksum_ctl(&ctl, 0); //enable checksum verification
    }
    else
    {
        ctl.action = NIDS_DONT_CHKSUM;
        nids_register_chksum_ctl(&ctl, 1); //disable checksum verification
    }

    return;
}

#if APM_DEBUG_UDP
#if 0
FR_STATIC char *adres(struct tuple4 addr)
{
    FR_STATIC char buf[256];
    strcpy (buf, int_ntoa (addr.saddr));
    sprintf (buf + strlen (buf), ",%i,", addr.source);
    strcat (buf, int_ntoa (addr.daddr));
    sprintf (buf + strlen (buf), ",%i", addr.dest);
    return buf;
}
#endif

FR_STATIC void __frame_udp_callback(struct tuple4 *addr, char *buf, int len, struct ip *iph)
{
    //char arr_buff[1024];
    //int i_len=0;
    //
    //strcpy (arr_buff, adres(*addr));
    //i_len = strlen(arr_buff);
    //
    //if(len >0)
    //{
    //    strcat(arr_buff, " ");
    //    i_len++;
    //    memcpy(arr_buff+i_len, buf, len);
    //    i_len += len;
    //    arr_buff[i_len] = '\0';
    //}
    //
    //fprintf (stderr, "udp [%s]\n", arr_buff);
    __frame_packet_stata_add(APM_CONNECT_ESTABLISHED);
    return;
}
#endif

/*******************************************************************************
*  FUNC     :  tcp层进行协议分析
*  ARGS     :  p_st_tcp                 (struct tcp_stream *)
*           :  this_time_not_needed     (void **)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_tcp_callback(struct tcp_stream *p_st_tcp, void ** this_time_not_needed)
{
    struct half_stream *p_st_half;
    int i_ret_fun=0, i_flag_filtered=FR_NO;
    struct ethhdr *p_st_ether_hdr=NULL;
    char *p_src_mac=NULL, *p_dst_mac=NULL;
    struct timeval st_timeval_pkg;
    Conntrack *p_st_ct=NULL;

    //获取数据包时间
    if(nids_last_pcap_header)
        st_timeval_pkg = nids_last_pcap_header->ts;
    else
        gettimeofday (&st_timeval_pkg, NULL);

    p_st_ether_hdr = (struct ethhdr *)(nids_last_pcap_data);
    //frdbg("nids_linkoffset=%d src=[" FRMAC_FMT "] dst=[" FRMAC_FMT "] %ld.%06ld\n"
    //        , nids_linkoffset, FRMAC_ARG(p_st_ether_hdr->h_source), FRMAC_ARG(p_st_ether_hdr->h_dest)
    //        , st_timeval_pkg.tv_sec, st_timeval_pkg.tv_usec);
    if(nids_linkoffset == 14 || nids_linkoffset == 18) //Regular ethernet; 802.1Q VLAN
    {
        p_src_mac = (char *)p_st_ether_hdr->h_source;
        p_dst_mac = (char *)p_st_ether_hdr->h_dest;
    }

    //数据包过滤
    if(p_st_tcp->client.collect || p_st_tcp->server.collect || p_st_tcp->server.collect_urg )
        i_flag_filtered = FR_YES;
    #ifdef WE_WANT_URGENT_DATA_RECEIVED_BY_A_CLIENT
        if(p_st_tcp->client.collect_urg)
            i_flag_filtered = FR_YES;
    #endif
    //已经过滤过的数据包，不需要再次过滤
    if(i_flag_filtered == FR_NO)
    {
        i_ret_fun = apm_do_filter(p_st_ether_hdr->h_source, IPPROTO_TCP
                                , p_st_tcp->addr.saddr, p_st_tcp->addr.daddr
                                , p_st_tcp->addr.source, p_st_tcp->addr.dest, -1);
        if(i_ret_fun == -1) //没有查询到
        {
            i_ret_fun = apm_do_filter(p_st_ether_hdr->h_dest, IPPROTO_TCP
                                    , p_st_tcp->addr.daddr, p_st_tcp->addr.saddr
                                    , p_st_tcp->addr.dest, p_st_tcp->addr.source, FR_YES); //默认通过
        }
        if(i_ret_fun != FR_YES)
            return;
    }

    //连接正式建立成功
    if(p_st_tcp->nids_state == NIDS_JUST_EST)
    {
        p_st_tcp->client.collect=1;
        p_st_tcp->server.collect=1;
        p_st_tcp->server.collect_urg=1;
        #ifdef WE_WANT_URGENT_DATA_RECEIVED_BY_A_CLIENT
                p_st_tcp->client.collect_urg=1;
        #endif

        __frame_packet_stata_add(APM_CONNECT_ESTABLISHED);
        //增加连接
        if(p_st_tcp->client.count_new)
            p_st_ct = frct_add(p_src_mac,p_dst_mac, IPPROTO_TCP
                            , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                            , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                            , FR_NO, FRANALYZ_CMD_UNKNOWN
                            , FR_YES, APM_CONNECT_ESTABLISHED, NULL, 0, st_timeval_pkg);
        else
            p_st_ct = frct_add(p_src_mac,p_dst_mac, IPPROTO_TCP
                            , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                            , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                            , FR_NO, FRANALYZ_CMD_UNKNOWN
                            , FR_YES, APM_CONNECT_ESTABLISHED, NULL, 0, st_timeval_pkg);
        //如果是新增加，则上报数据
        if(p_st_ct)
        {
            frreport_mng_send_conn(p_st_ct, APM_CONNECT_ESTABLISHED, st_timeval_pkg);
        }
        frct_put(p_st_ct);

        //frct_hash_output();
        return;
    }

    //有处理数据
    if(p_st_tcp->nids_state == NIDS_DATA)
    {
        __frame_packet_stata_add(APM_CONNECT_ESTABLISHED);
        if (p_st_tcp->client.count_new)
            p_st_half = &p_st_tcp->client;
        else
            p_st_half = &p_st_tcp->server;
        if(p_st_tcp->client.count_new)
            frct_add(p_src_mac,p_dst_mac, IPPROTO_TCP
                    , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                    , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                    , FR_YES, FRANALYZ_CMD_DATA
                    , FR_NO, APM_CONNECT_ESTABLISHED, p_st_half->data, p_st_half->count_new, st_timeval_pkg);
        else
            frct_add(p_src_mac,p_dst_mac, IPPROTO_TCP
                    , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                    , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                    , FR_YES, FRANALYZ_CMD_DATA
                    , FR_NO, APM_CONNECT_ESTABLISHED, p_st_half->data, p_st_half->count_new, st_timeval_pkg);
        //FRPRINT_BIN("tcp data:", p_st_half->data, p_st_half->count_new);
        //frct_hash_output();
        return;
    }

    //连接释放
    if(p_st_tcp->nids_state == NIDS_CLOSE || p_st_tcp->nids_state == NIDS_RESET)
    {
        //p_st_ct = frct_get(IPPROTO_TCP, p_st_tcp->addr.saddr, p_st_tcp->addr.source
        //                 , p_st_tcp->addr.daddr, p_st_tcp->addr.dest );
        //if(p_st_ct)
        //    p_st_ct->st_connection_fin_time = st_timeval_pkg;
        //frct_put(p_st_ct);
        __frame_packet_stata_add(APM_CONNECT_CLOSED);
        frct_del(IPPROTO_TCP
                , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                , st_timeval_pkg);

        return;
    }

    return ;
}

/*******************************************************************************
*  FUNC     :  增加tcp的新建连接
*  ARGS     :  p_st_iphdr    (struct ip *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_add_tcp_new(struct ip *p_st_iphdr, struct tcp_stream *p_st_tcp)
{
    struct tcphdr *p_st_tcphdr = NULL;
    int i_ret_fun=0, i_flag_filtered = FR_NO;
    struct ethhdr *p_st_ether_hdr=NULL;
    char *p_src_mac=NULL, *p_dst_mac=NULL;
    struct timeval st_timeval_pkg;
    u_short src_port, dst_port;

    if(p_st_iphdr == NULL || p_st_iphdr->ip_p != IPPROTO_TCP)
        return;

    if(nids_last_pcap_header)
        st_timeval_pkg = nids_last_pcap_header->ts;
    else
        gettimeofday (&st_timeval_pkg, NULL);

    p_st_ether_hdr = (struct ethhdr *)(nids_last_pcap_data);
    //frdbg("nids_linkoffset=%d src=[" FRMAC_FMT "] dst=[" FRMAC_FMT "] %ld.%06ld\n"
    //        , nids_linkoffset, FRMAC_ARG(p_st_ether_hdr->h_source), FRMAC_ARG(p_st_ether_hdr->h_dest)
    //        , st_timeval_pkg.tv_sec, st_timeval_pkg.tv_usec);

    if(nids_linkoffset == 14 || nids_linkoffset == 18) //Regular ethernet; 802.1Q VLAN
    {
        p_src_mac = (char *)p_st_ether_hdr->h_source;
        p_dst_mac = (char *)p_st_ether_hdr->h_dest;
    }

    p_st_tcphdr = (struct tcphdr *)( (u_char *)p_st_iphdr + 4 * p_st_iphdr->ip_hl);

    //数据包过滤
    if(p_st_tcp)
    {
        if(p_st_tcp->client.collect || p_st_tcp->server.collect || p_st_tcp->server.collect_urg )
            i_flag_filtered = FR_YES;
        #ifdef WE_WANT_URGENT_DATA_RECEIVED_BY_A_CLIENT
            if(p_st_tcp->client.collect_urg)
                i_flag_filtered = FR_YES;
        #endif
    }
    
    #ifdef FRLINUX4
        src_port = p_st_tcphdr->source;
        dst_port = p_st_tcphdr->dest;
    #else
        src_port = p_st_tcphdr->th_sport;
        dst_port = p_st_tcphdr->th_dport;
    #endif
    
    //已经过滤过的数据包，不需要再次过滤
    if(i_flag_filtered == FR_NO)
    {
        i_ret_fun = apm_do_filter(p_st_ether_hdr->h_source, IPPROTO_TCP
                                , p_st_iphdr->ip_src.s_addr, p_st_iphdr->ip_dst.s_addr
                                , ntohs(src_port), ntohs(dst_port), -1);
        if(i_ret_fun == -1) //没有查询到
        {
            i_ret_fun = apm_do_filter(p_st_ether_hdr->h_dest, IPPROTO_TCP
                                    , p_st_iphdr->ip_dst.s_addr, p_st_iphdr->ip_src.s_addr
                                    , ntohs(dst_port), ntohs(src_port), FR_YES); //默认通过
        }
        if(i_ret_fun != FR_YES)
            return;
    }

    //if ((p_st_tcphdr->th_flags & TH_SYN) &&
    //!(p_st_tcphdr->th_flags & TH_ACK) &&
    //!(p_st_tcphdr->th_flags & TH_RST))
    {
        Conntrack *p_st_ct=NULL;

        __frame_packet_stata_add(APM_CONNECT_SYN_SENT);
        //增加连接
        p_st_ct = frct_add(p_src_mac, p_dst_mac, p_st_iphdr->ip_p
                        , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                        , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                        //, p_st_iphdr->ip_src.s_addr, ntohs(src_port)
                        //, p_st_iphdr->ip_dst.s_addr, ntohs(dst_port)
                        , FR_YES, FRANALYZ_CMD_SYN
                        , FR_YES, APM_CONNECT_SYN_SENT, NULL, 0, st_timeval_pkg);

        //frct_hash_output();
        //新增连接,上报数据
        if(p_st_ct)
            frreport_mng_send_conn(p_st_ct, APM_CONNECT_SYN_SENT, st_timeval_pkg);
        frct_put(p_st_ct);
    }

    return;
}

/*******************************************************************************
*  FUNC     :  信号处理
*  ARGS     :  dunno    (信号量)
*  RTN      :  
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_sig(int dunno)
{
    switch (dunno) {
        case SIGHUP:
            g_i_flag_run = 0;
            event_base_loopbreak(g_p_st_ebase);
            printf("SIGHUP(wait %d sec)\n", g_i_after_nids_sec);
            break;
        case SIGINT:
            g_i_flag_run = 0;
            event_base_loopbreak(g_p_st_ebase);
            printf("SIGINT(wait %d sec)\n", g_i_after_nids_sec);
            break;
        case SIGQUIT:
            g_i_flag_run = 0;
            event_base_loopbreak(g_p_st_ebase);
            printf("SIGQUIT(wait %d sec)\n", g_i_after_nids_sec);
            break;
        case SIGPIPE:
            printf("SIGPIPE\n");
            break;
        default:
            break;
    }
    return;
}

/*******************************************************************************
*  FUNC     :  应用程序退出
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frame_cmd_exist(void )
{

    g_i_flag_run = 0;
    event_base_loopbreak(g_p_st_ebase);

    return;
}

/*******************************************************************************
*  FUNC     :  启动cui 命令行服务
*  ARGS     :  arg    (void *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_cmd_line(void *arg)
{

    FRLOG_INFO("cmd_line start");
    frcmd_server_start(st_apm_params.ui_cmd_srv_port);
    FRLOG_INFO("cmd_line end");

    pthread_exit(0);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  触发timer事件
*  ARGS     :  arg    (void *)
*  RTN      :  
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_do_timer(void *arg)
{
    //struct timeval st_delay = {2, 0};
    
    g_i_task_chk_timer = FR_YES;
    pthread_detach(pthread_self());

    FRLOG_INFO("event_base_dispatch start");
    
    while(g_i_flag_run)
    {
        //if(nids_params.filename)
        //    event_base_loopexit(g_p_st_ebase, &st_delay);
        event_base_dispatch(g_p_st_ebase);
        usleep(100000);
    }
    g_i_task_chk_timer = FR_NO;
    FRLOG_INFO("event_base_dispatch end");
    pthread_exit(0);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  frame初始化
*  ARGS     :
*  RTN      :  FR_SUCC:成功, FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frame_init(int i_flag_run_dumpfile)
{
    int i_ret_fun=0, i_loop=0;
    
    //初始化libevent
    if(evthread_use_pthreads())
    {
        FRLOG_ERROR_DETAIL("evthread_use_pthreads err");
        return FR_FAIL;
    }

    #ifdef FRDBG_CT_DBG
    event_enable_debug_mode();
    #endif

    if(g_p_st_ebase == NULL)
        g_p_st_ebase = event_base_new();

    if(g_p_st_ebase == NULL)
    {
        FRLOG_ERROR_DETAIL("event_base_new err");
        return FR_FAIL;
    }
    //初始化时钟管理
    i_ret_fun = frtimer_init();
    if(i_ret_fun != FR_SUCC)
    {
        event_base_free(g_p_st_ebase);
        FRLOG_ERROR_DETAIL("frtimer_init err");
        return FR_FAIL;
    }
    //初始化zmq
    i_ret_fun = frreport_mng_conn_init();
    if(i_ret_fun != FR_SUCC)
    {
        frtimer_destory();
        event_base_free(g_p_st_ebase);
        FRLOG_ERROR_DETAIL("frreport_conn_init err");
        return FR_FAIL;
    }

    //创建任务处理线程
    g_p_thread_id_do_task = frmalloc(sizeof(pthread_t) * g_i_do_task_cnt);
    if(g_p_thread_id_do_task == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        goto ERROR_EBASE;
    }
    memset(g_p_thread_id_do_task, '\0', sizeof(pthread_t) * g_i_do_task_cnt);
    for(i_loop=0; i_loop<g_i_do_task_cnt; i_loop++)
    {
        i_ret_fun = pthread_create(g_p_thread_id_do_task+i_loop, NULL, frtask_do, NULL);
        if(i_ret_fun)
        {
            *(g_p_thread_id_do_task+i_loop) = 0;
            FRLOG_ERROR_DETAIL("pthread_create frtask_do num=[%d] err", i_loop);
            continue;
        }
        g_ui_threads++;
    }

    //时钟检查线程
    i_ret_fun = pthread_create(&g_thread_id_do_timer, NULL, __frame_do_timer, NULL);
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("pthread_create __frame_do_timer err");
        goto ERROR_THREAD;
    }
    g_ui_threads += 1;
    //命令行对应
    //if(nids_params.filename == NULL)
    {
        i_ret_fun = pthread_create(&g_thread_id_cmd_line, NULL, __frame_cmd_line, NULL);
        if(i_ret_fun)
        {
            FRLOG_ERROR_DETAIL("pthread_create __frame_cmd_line err");
            goto ERROR_THREAD;
        }
        g_ui_threads += 1;
    }

    //过滤规矩加载
    i_ret_fun = apm_filter_init();
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("apm_filter_init err");
        goto ERROR_THREAD;
    }
    i_ret_fun = apm_filter_load();
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("apm_filter_load err");
        apm_filter_destroy();
        goto ERROR_THREAD;
    }

    //模块信息初始化
    frmodule_mng_init();
    i_ret_fun = frproto_mng_init();
    if(i_ret_fun == FR_FAIL)
    {
        apm_filter_destroy();
        goto ERROR_THREAD;
    }
    //为了调试其他模块,模块加载出错,程序也继续
    frmodule_cfg_load(FR_NO);
    frproto_cfg_load(FR_NO);
    frproto_l7default_load(FR_NO);

    //加载模块统计
    __frame_stat_init();
    i_loop=0;
    i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_module, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_stat_module err");
    else
    {
        i_loop++;
        g_ui_threads++;
    }
    i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_system, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_stat_system err");
    else
    {
        i_loop++;
        g_ui_threads++;
    }
    i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_thread, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_stat_thread err");
    else
    {
        i_loop++;
        g_ui_threads++;
    };
    i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_server, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_stat_server err");
    else
    {
        i_loop++;
        g_ui_threads++;
    };
#ifdef FRDBG_PACKET_STAT
    if(i_flag_run_dumpfile == FR_NO)
    {
        i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_packet, NULL);
        if(i_ret_fun)
            FRLOG_ERROR_DETAIL("pthread_create __frame_stat_packet err");
        else
        {
            i_loop++;
            g_ui_threads++;
        }
    }
#endif
    //任务管理加载
    i_ret_fun = frtask_mng_init();
    if(i_ret_fun == FR_FAIL)
    {
        __frame_stat_destory();
        frproto_mng_destory();
        apm_filter_destroy();
        goto ERROR_THREAD;
    }

    i_ret_fun = frct_init(st_apm_params.ui_ct_hash_size);
    if(i_ret_fun == FR_FAIL)
    {
        __frame_stat_destory();
        frtask_mng_destory();
        frproto_mng_destory();
        apm_filter_destroy();
        goto ERROR_THREAD;
    }
    //frct_expect_init(st_apm_params.ui_relative_timeout);
    
    return FR_SUCC;

ERROR_THREAD:
    g_i_flag_run=0;
    frdbg("pthread_join start\n");
    if(g_thread_id_cmd_line)
        pthread_join(g_thread_id_cmd_line, NULL);
    for(i_loop=0; i_loop<APM_STAT_CNT; i_loop++)
    {
        if(g_thread_id_stat[i_loop])
            pthread_join(g_thread_id_stat[i_loop], NULL);
    }

    for(i_loop=0; g_p_thread_id_do_task && i_loop<g_i_do_task_cnt; i_loop++)
    {
        if(g_p_thread_id_do_task[i_loop])
            pthread_join(g_p_thread_id_do_task[i_loop], NULL);
    }
    if(g_p_thread_id_do_task)
    {
        frfree(g_p_thread_id_do_task);
        g_p_thread_id_do_task = NULL;
    }

    //时钟检查线程退出
    //if(g_thread_id_do_timer)
    //    pthread_join(g_thread_id_do_timer, NULL);
    i_loop = 0;
    while(g_i_task_chk_timer == FR_YES && i_loop++ < 10)
    {
        event_base_loopbreak(g_p_st_ebase);
        sleep(1);
    }
    if(g_i_task_chk_timer == FR_YES && i_loop >= 10)
        FRLOG_WARN("event_base_dispatch fail");

    frdbg("pthread_join end\n");

ERROR_EBASE:
    if(g_p_st_ebase)
    {
        frreport_mng_conn_destory();
        frtimer_destory();
        event_base_free(g_p_st_ebase);
    }

    return FR_FAIL;
}


/*******************************************************************************
*  FUNC     :  frame资源释放
*  ARGS     :  
*  RTN      :  
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_destory(void)
{
    int i_loop;

    FRLOG_INFO("pthread_join start");

    if(g_thread_id_cmd_line)
        pthread_join(g_thread_id_cmd_line, NULL);
    for(i_loop=0; i_loop<APM_STAT_CNT; i_loop++)
    {
        if(g_thread_id_stat[i_loop])
            pthread_join(g_thread_id_stat[i_loop], NULL);
    }

    //任务分配线程
    for(i_loop=0; g_p_thread_id_do_task && i_loop<g_i_do_task_cnt; i_loop++)
    {
        if(g_p_thread_id_do_task[i_loop])
            pthread_join(g_p_thread_id_do_task[i_loop], NULL);
    }
    if(g_p_thread_id_do_task)
    {
        frfree(g_p_thread_id_do_task);
        g_p_thread_id_do_task = NULL;
    }
    FRLOG_INFO("pthread_join end");

    //时钟检查线程退出
    //if(g_thread_id_do_timer)
    //    pthread_join(g_thread_id_do_timer, NULL);
    i_loop = 0;
    while(g_i_task_chk_timer == FR_YES && i_loop++ < 10)
    {
        event_base_loopbreak(g_p_st_ebase);
        sleep(1);
    }
    if(g_i_task_chk_timer == FR_YES && i_loop >= 10)
        FRLOG_WARN("event_base_dispatch fail");

    frtask_mng_destory();
    //frct_expect_destory();
    //调试用输出
    //frct_hash_output();
    frct_destroy();

    frproto_mng_destory();
    frmodule_mng_destory();
    apm_filter_destroy();
    __frame_stat_destory();

    if(g_p_st_ebase)
    {
        frreport_mng_conn_destory();
        frtimer_destory();
        event_base_free(g_p_st_ebase);
    }

    return;
}

/*******************************************************************************
*  FUNC     :  抓包分析
*  ARGS     :  p_pcap_filename      (测试用pcap文件)
*  RTN      :  FR_SUCC:成功, FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frame_do_analyser( int i_after_nids_sec
                                 , int i_dumpfile_times)
{
    int i_ret=FR_SUCC, i_ret_fun = 0, i_loop=0, i_flag_run_dumpfile;
    struct timeval st_time_now;

    if(nids_params.filename)
        i_flag_run_dumpfile = FR_YES;
    else
        i_flag_run_dumpfile = FR_NO;

    i_ret_fun = __frame_init(i_flag_run_dumpfile);
    if(i_ret_fun == FR_FAIL)
    {
        FRLOG_ERROR_DETAIL("frame_init err");
        return FR_FAIL;
    }

    if(i_dumpfile_times <0)
        i_dumpfile_times = 1;

    FRLOG_INFO("apm analyse run...");
    printf("apm analyse run...\n");
    
    signal(SIGHUP, __frame_sig);
    signal(SIGINT, __frame_sig);
    signal(SIGQUIT, __frame_sig);
    signal(SIGPIPE, __frame_sig);
    signal(SIGUSR1, __frame_sig);

    i_loop=1;
    do
    {
        if (!nids_init ())
        {
            FRLOG_ERROR_DETAIL("nids_init err[%s]", nids_errbuf);
            frwarn("nids_init err[%s]", nids_errbuf);
            i_ret = FR_FAIL;
            goto END;
        }

        apm_register_tcp_new(__frame_add_tcp_new);

        nids_register_tcp(__frame_tcp_callback);
        #if APM_DEBUG_UDP
        nids_register_udp(__frame_udp_callback);
        #endif

        //调试数据包
        if(i_flag_run_dumpfile==FR_YES)
        {
            nids_run ();
        }
        else
        {
            while(g_i_flag_run)
            {
                //nids_next();
                nids_dispatch(1);
            }
            nids_exit();
        }

        if(i_dumpfile_times >0 && ++i_loop > i_dumpfile_times)
            break;
    } while (g_i_flag_run && i_flag_run_dumpfile==FR_YES);

    if(i_flag_run_dumpfile == FR_NO)
    {
        gettimeofday(&st_time_now, NULL);
        __frame_stat_packet_report(&st_time_now);
    }
    event_base_loopbreak(g_p_st_ebase);
    sleep(i_after_nids_sec);

    #ifdef FRDBG_CT_PRINT
    //frct_expect_output(NULL);
    //frct_hash_output(NULL);
    #endif

END:
    g_i_flag_run = 0;
    sleep(1);

    __frame_destory();
    FRLOG_INFO("apm analyse end...");
    printf("apm analyse end...\n");
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  显示命令帮助
*  ARGS     :  p_pgname      (运行查询名称)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __usage(char *p_pgname)
{
    printf("Usage: %s [OPTION]... \n", p_pgname);
    printf("param info\n");
    printf("\t-d 测试用pcap文件\n");
    printf("\t-t 测试用pcap文件运行次数(0:一直运行该pcap文件).(default 1)\n");
    printf("\t-n 不进行checksum检查.\n");
    printf("\t-m 设置主框架内存大小(M).(default 100Mbyte)(eg. -m 200)\n");
    printf("\n");
    printf("\t-f 抓包过滤规则.(eg. -f \"tcp port 80 host 172.16.0.56\" )\n");
    printf("\t-i 网卡设备名.(eg. -i eth2). (default eth0)\n");
    printf("\n");
    printf("\t-w 等待多久退出程序(eg. -w 15). (default 10sec).\n");
    printf("\t-h help.\n");
    printf("\n");
    printf("\t--help help.\n");

    return;
}

FR_STATIC void __frame_nids_syslog(int type, int errnum, struct ip *iph, void *data)
{
    return;
}

/*******************************************************************************
*  FUNC     :  apm主程序
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
/*
int main( int argc, char *argv[] )
{
    int i_flag_param=0, i_flag_chksum = FR_YES, i_flag_exit=FR_NO, i_loop;
    char *p_dumpfile=NULL, *p_pcap_filter=NULL;
    int i_dumpfile_times=1;
    unsigned int ui_mempool_size = 1024*1024*100;//100 Mbyte
    int i_ret_fun=0;
    int i_after_nids_sec=2; //默认nids退出后等待2sec
    char *p_dev;
    char *p_short_opts = "d:f:m:t:i:w:nh";
    struct option st_long_opts[] = { {"help", 0, NULL, 'H'},
                                     {NULL, 0, NULL, 0} };


    p_dev="eth0";
    //获取程序参数
    while((i_flag_param=getopt_long(argc, argv, p_short_opts, st_long_opts, NULL) )!=-1)
    {
        switch(i_flag_param)
        {
            case 'd': //测试用pcap文件
              //frdbg("option d:[%s]\n",optarg);
              p_dumpfile = optarg;
              break;
            case 'f': //抓包过滤规则
              //frdbg("option d:[%s]\n",optarg);
              p_pcap_filter = optarg;
              break;
            case 'H':
            case 'h':
              __usage(argv[0]);
              i_flag_exit = FR_YES;
              break;
            case 'i': //网卡设备名
              p_dev = optarg;
              break;
            case 'm': //缓存池空间大小
              ui_mempool_size = atoi(optarg);
              ui_mempool_size = ui_mempool_size * 1024 * 1024;
              if(ui_mempool_size < 1024*1024*10) //10Mbyte
                  ui_mempool_size = 1024*1024*100;//100 Mbyte
              break;
            case 'n': //不进行checksum检查
              i_flag_chksum = FR_NO;
              break;
            case 't': //测试用pcap文件运行次数
              i_dumpfile_times = atoi(optarg);
              if(i_dumpfile_times < 0)
                  i_dumpfile_times = 1;
              break;
            case 'w': //退出程序的时间
              //frdbg("option d:[%s]\n",optarg);
              i_after_nids_sec = atoi(optarg);
              if(i_after_nids_sec <=0)
                  i_after_nids_sec = 10;
              else if(i_after_nids_sec > 600)
                  i_after_nids_sec = 600; //10分钟
              break;
            default:
              break;
        }
        //frdbg("optopt+%c\n",optopt);
    }

    if(i_flag_exit == FR_YES)
        return 0;
    nids_params.device = p_dev;

    //nids log不出力
    nids_params.syslog = __frame_nids_syslog;

    //更改当前程序的工作目录
    {
        unsigned int ui_buff_size = 1000;
        char *p_buff = malloc(ui_buff_size);
        if(p_buff == NULL)
        {
            frwarn("main malloc err\n");
            return 0;
        }
        //memset(p_buff, '\0', ui_buff_size);
        i_ret_fun = frget_absdir(argv[0], p_buff, ui_buff_size-1);
        if(i_ret_fun == FR_SUCC)
            chdir(p_buff);
        free(p_buff);
    }

    //配置内存
    i_ret_fun = fr_slab_init(ui_mempool_size, "framework");
    if(i_ret_fun == FR_FAIL)
    {
        FRLOG_ERROR_DETAIL("fr_slab_init err");
        frwarn("fr_slab_init err\n");
        return 0;
    }

    i_ret_fun = frlog_open(APM_CFG_FILENAME_ZLOG, "apm_framework");
    if (i_ret_fun)
    {
        frwarn("log_open failed\n");
        fr_slab_destroy();
        return 1;
    }

    //获取配置信息
    frame_params_get();
    frame_params_output();
    g_i_do_task_cnt = st_apm_params.ui_do_task_cnt;

    //配置nids环境
    FRLOG_INFO("p_dumpfile=[%s] p_pcap_filter=[%s] dev=[%s]", p_dumpfile, p_pcap_filter, nids_params.device);
    if(p_dumpfile)
        nids_params.filename = p_dumpfile;
    if(p_pcap_filter)
        nids_params.pcap_filter = p_pcap_filter;
    if(i_flag_chksum == FR_NO)
        __frame_chg_chksum(FR_NO);
    nids_params.scan_num_hosts = 0;

    //运行抓包分析
    memset(&g_st_apm_packets, 0x00, sizeof(Frapm_packets));
    gettimeofday (&g_st_apm_packets.st_start_sec, NULL);

    for(i_loop=0; i_loop < APM_STAT_CNT; i_loop++)
        g_thread_id_stat[i_loop]=0;

    g_i_after_nids_sec = i_after_nids_sec;
    //防止统计函数第1次计算时，由于时间片过小，计算误差比较大
    sleep(1);
    __frame_do_analyser(i_after_nids_sec, i_dumpfile_times);

    frlog_close();
    fr_slab_destroy();
    return 0;
}
*/